package pl.streamsoft.currencyApp.dao;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Filter;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import pl.streamsoft.currencyApp.model.Country;
import pl.streamsoft.currencyApp.model.Currency;

public class CurrencyDAO implements ICurrencyDAO {
	private HibernateUtil hibernateUtil;
	
	public CurrencyDAO(){
		this.hibernateUtil = new HibernateUtil();
	}
	
	@Override
	public void insertCurrencyIntoDB(Currency currency) {
		Session session = hibernateUtil.getOpenedSession();
		try{
			session.save(currency);
			hibernateUtil.closeSession();
		}
		catch(Exception e){
			hibernateUtil.rollBackTransaction();
			hibernateUtil.closeSession();
		}
	}

	@Override
	public void deleteCurrency(String name, String code, Date date) throws RuntimeException {
		try {
			Session session = hibernateUtil.getOpenedSession();
			Query query = session.getNamedQuery("Currency.deleteWhereNameAndCodeAndDateAreLike");
			query.setParameter("name", name);
			query.setParameter("code", code);
			query.setParameter("date", date);
			query.executeUpdate();
			hibernateUtil.closeSession();
		} 
		catch (Exception e) {
			hibernateUtil.rollBackTransaction();
			hibernateUtil.closeSession();
			throw new RuntimeException("Can't delete currency");
		}
	}


	// 			using of flush and clear
	//	--									--
	@Override
	public void saveAllCurrencies(List<Currency> listOfCurrencies) throws RuntimeException {
		Session session = hibernateUtil.getOpenedSession();
		try{
			int i = 0;
			for(Currency el: listOfCurrencies){
				el.setId(i);
				session.save(el);
				i++;
				if(i%2 == 0){
					session.flush();
					session.clear();
				}
			}
			
			hibernateUtil.closeSession();
		}
		catch(Exception e){
			hibernateUtil.rollBackTransaction();
			hibernateUtil.closeSession();
			throw new RuntimeException("Can't save currencies into database!");
		}
	}

	@Override
	public void deleteAllCurrenciesFromDB() throws RuntimeException {
		Session session = hibernateUtil.getOpenedSession();
		try{
			Query query = session.getNamedQuery("Currency.deleteAllCurencies");
			query.executeUpdate();
						
			hibernateUtil.closeSession();
		}
		catch(Exception e){
			hibernateUtil.rollBackTransaction();
			hibernateUtil.closeSession();
			throw new RuntimeException("Can't delete all currencies!");
		}
	}

	@Override
	public List<Currency> getAllCurrenciesFromInterval(String from, String to) throws RuntimeException {
		try{
			Session session = hibernateUtil.getOpenedSession();
			Query query = session.getNamedQuery("Currency.gettingAllCurrenciesWhereAvarageRateIsBetween");
			query.setBigDecimal(0, new BigDecimal(from));
			query.setBigDecimal(1, new BigDecimal(to));
			List<Currency> listOfCurrencies = (List<Currency>) query.list();
			
			hibernateUtil.closeSession();
			return listOfCurrencies;
		}
		catch(Exception e){
			hibernateUtil.closeSession();
			hibernateUtil.rollBackTransaction();
			throw new RuntimeException("Can't get currencies where avarage rate is between "+from+" and "+to+" !");	
		}
	}

	//using filter
	@Override
	public List<Currency> getAllCurrenciesWhereNameMatchesWord(String word) throws RuntimeException {
		try{
			Session session = hibernateUtil.getOpenedSession();
			Filter filter = session.enableFilter("matchesFilter");
			session.getEnabledFilter("matchesFilter").setParameter("matchesParam", word);

			Query query = session.createQuery("from Currency");
			/*
			Query query = session.getNamedQuery("Currency.getAllCurrenciesWhereNameMatches");
			query.setParameter("word", "%"+word+"%");*/
			List<Currency> listOfCurrencies = (List<Currency>) query.list();
			
			hibernateUtil.closeSession();
			return listOfCurrencies;
		}
		catch(Exception e){
			hibernateUtil.closeSession();
			hibernateUtil.rollBackTransaction();
			throw new RuntimeException("Can't find currencies where name matches: "+word+" !");
		}
	}
	
	@Override
	public void deleteCurrencyFromCountry(String countryName,
			Currency currency) throws RuntimeException {
		
		Session session = hibernateUtil.getOpenedSession();
		try{
			Query query = session.createQuery("from Country where name = ?");
			query.setString(0, countryName);
			query.setMaxResults(1);
			Country country = (Country) query.uniqueResult();
			
			if(country.getCurrencyList().contains(currency)){
				country.getCurrencyList().remove(currency);
			}
			
			session.saveOrUpdate(country);
			hibernateUtil.closeSession();
		}
		catch(Exception e){
			hibernateUtil.rollBackTransaction();
			hibernateUtil.closeSession();
			throw new RuntimeException("Can't delete currency from country!");
		}
	}

	@Override
	public List<Currency> getCurrenciesFromDate(Date date) throws RuntimeException {
		try{
			Session session = hibernateUtil.getOpenedSession();
			Query query = session.getNamedQuery("Currency.getAllWhereDateEq");
			query.setParameter("date", date);
			/*Criteria criteria = session.createCriteria(Currency.class);
			criteria.add(Restrictions.eq("date", date));*/
			List<Currency> listOfCurrencies = (List<Currency>) query.list();
			
			hibernateUtil.closeSession();
			return listOfCurrencies;
		}
		catch(Exception e){
			hibernateUtil.closeSession();
			throw new RuntimeException("Can't get currencies from date: "+date.toLocaleString());
		}
	}

	@Override
	public List<Currency> getCurrencyFromDateToDate(Date from, Date to) throws RuntimeException {
		try{
			Session session = hibernateUtil.getOpenedSession();
			Query query = session.getNamedQuery("Currency.getAllCurrenciesWhereDateIsBetween");
			query.setParameter("from", from);
			query.setParameter("to", to);
			List<Currency> listOfCurrencies = (List<Currency>) query.list();
			
			hibernateUtil.closeSession();
			return listOfCurrencies;
		}
		catch(Exception e){
			hibernateUtil.closeSession();
			throw new RuntimeException("Can't find currencies between "+from.toLocaleString()+" and "+to.toLocaleString()+" !");
		}
	}

	@Override
	public Currency getCurrencyFromDBByCodeAndDate(String code, Date date) throws RuntimeException {
		try{
			Session session = hibernateUtil.getOpenedSession();
			Query query = session.getNamedQuery("Currency.getAllCurrenciesWhereCodeAndDateIsLike");
			query.setString(0, code);
			query.setDate(1, date);
			query.setMaxResults(1);
			Currency currency = (Currency) query.uniqueResult();
			hibernateUtil.closeSession();
			return currency;
		}
		catch(Exception e){
			hibernateUtil.closeSession();
			throw new RuntimeException("Currency with code: "+code+" and date "+date.toString()+ " is not existing in database!");
		}
	}

	//		dirty checking method
	// -- 							--
	@Override
	public void findAndChangeCurrencyInfo(Currency newCurrency,Date dateOfOldCurrency, String codeOfOldCurrency) throws RuntimeException{
		Currency currencyChanged = getCurrencyFromDBByCodeAndDate(codeOfOldCurrency,dateOfOldCurrency);
		try {
			
			Session session = hibernateUtil.getOpenedSession();
			currencyChanged.setName(newCurrency.getName());
			currencyChanged.setCurrencyCode(newCurrency.getCurrencyCode());
			currencyChanged.setConverter(newCurrency.getConverter());
			currencyChanged.setAverageRate(newCurrency.getAverageRate());
			currencyChanged.setDate(newCurrency.getDate());
			session.update(currencyChanged);
			
			//dirty checking
			currencyChanged.setName(newCurrency.getName());
			currencyChanged.setCurrencyCode("CODE");
			hibernateUtil.closeSession();
		} 
		catch (Exception e) {
			hibernateUtil.closeSession();
			throw new RuntimeException("Can't change currency info!");
		}
	}
}
